package com.ttxs.uaa.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ttxs.common.core.constant.Common;
import com.ttxs.common.core.constant.SecurityConstant;
import com.ttxs.common.core.exception.RemoteLoginException;
import com.ttxs.common.core.utils.AuthUtils;
import com.ttxs.common.core.vo.LoginUser;
import com.ttxs.common.core.vo.RemoteLoginVO;
import com.ttxs.common.core.vo.Token;
import com.ttxs.uaa.entity.SysMenu;
import com.ttxs.uaa.entity.SysPlatform;
import com.ttxs.uaa.entity.SysRole;
import com.ttxs.uaa.entity.SysUser;
import com.ttxs.uaa.mapper.SysMenuMapper;
import com.ttxs.uaa.mapper.SysRoleMapper;
import com.ttxs.uaa.mapper.SysUserMapper;
import com.ttxs.uaa.service.IRemoteUserService;
import com.ttxs.uaa.service.ISysPlatformService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 远程登录 服务实现类
 * 应用场景：用户在登录老系统后，通过feign的方式调用，方便在网关鉴权
 * </p>
 *
 * @author 天天向上
 * @since 2021-07-26
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class RemoteUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements IRemoteUserService {
    private final SysRoleMapper sysRoleMapper;
    private final SysMenuMapper sysMenuMapper;
    private final ISysPlatformService sysPlatformService;

    @Override
    public Token remoteLogin(RemoteLoginVO remoteLoginVO) {
        SysPlatform sysPlatform = getSysPlatform(remoteLoginVO.getPlatformName());
        SysUser user = getBaseMapper().selectOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUserName, remoteLoginVO.getUsername())
                .eq(SysUser::getPlatformId, sysPlatform.getPlatformId()));
        if (user == null) {
            throw new RemoteLoginException(remoteLoginVO.getUsername() + "平台用户不存在");
        } else if (!verifyPassword(remoteLoginVO, user.getPassword())) {
            throw new RemoteLoginException("用户密码与平台密码不匹配");
        } else if (user.getStatus().equals(Common.Status.STATUS_DISABLED)) {
            throw new RemoteLoginException(remoteLoginVO.getUsername() + "平台用户已停用");
        }
        // 获取用户角色名字列表，转换成字符串，用英文逗号分割
        String roleNames = getRoleNames(user);
        return createToken(sysPlatform, user, roleNames);
    }

    private boolean verifyPassword(RemoteLoginVO remoteLoginVO, String encodePassword) {
        String rawPassword = remoteLoginVO.getPassword();
        switch (remoteLoginVO.getAlg()) {
            case BCRYPT:
                return new BCryptPasswordEncoder().matches(rawPassword, encodePassword);
            case MD5:
                return DigestUtils.md5DigestAsHex(rawPassword.getBytes()).equals(encodePassword);
            default:
                return encodePassword.equals(rawPassword);
        }
    }

    private SysPlatform getSysPlatform(String platformName) {
        SysPlatform sysPlatform = sysPlatformService.getByPlatformName(platformName);
        if (sysPlatform == null) {
            throw new RemoteLoginException(platformName + "平台不存在");
        }
        if (sysPlatform.getStatus().equals(Common.Status.STATUS_DISABLED)) {
            throw new RemoteLoginException(platformName + "平台已停用");
        }
        return sysPlatform;
    }

    // 创建token，并缓存loginUser到redis
    private Token createToken(SysPlatform sysPlatform, SysUser user, String roleNames) {
        Set<String> urlPatterns =
                sysMenuMapper.selectListByRoleNames(user.getPlatformId(), roleNames.split(",")).stream()
                        .filter(item -> StringUtils.hasText(item.getApiUrl()))
                        .map(item -> getMethodAndUrl(item)).sorted()
                        .collect(Collectors.toCollection(LinkedHashSet::new));

        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getUserId());
        loginUser.setUsername(user.getUserName());
        loginUser.setNickName(user.getNickName());
        loginUser.setAuthorities(urlPatterns);
        loginUser.getExtra().put(Common.HttpHeaders.PLATFORM_ID, sysPlatform.getPlatformId());
        loginUser.getExtra().put(Common.HttpHeaders.PLATFORM_NAME, sysPlatform.getPlatformName());
        // 创建token和refreshToken，并缓存权限到redis
        return AuthUtils.createToken(loginUser);
    }

    private String getMethodAndUrl(SysMenu item) {
        if (StringUtils.hasText(item.getHttpMethod())) {
            return item.getHttpMethod().toUpperCase() + "_" + item.getApiUrl();
        }
        return "GET_" + item.getApiUrl();
    }

    private String getRoleNames(SysUser user) {
        List<SysRole> sysRoles = sysRoleMapper.selectByUserId(user.getUserId());
        return sysRoles.stream().map(r -> r.getRoleName()).collect(Collectors.joining(","));
    }

}
